<?php

namespace api\components;

use api\utils\LogUtil;
use Exception;
use SplFileObject;
use Yii;
use yii\base\Component;
use yii\helpers\ArrayHelper;
use yii\web\UploadedFile;

class FileServer extends Component
{
    public $host;
    public $appId;
    public $appKey;
    public $filePath; // 'http://10.89.1.161/api-v3/inner/events/getFile/f'

    //图片
    const FILE_TYPE_IMG = 1;
    //文件（默认）
    const FILE_TYPE_FILE = 2;
    //音频
    const FILE_TYPE_AUDIO = 3;
    //视频
    const FILE_TYPE_VEDIO = 4;

    const SHORT_CODE_PATH = '/api/files/getShortCodeFiles';
    const UPLOAD_URL = '/api/files/uploadFile';

    public function getPathInfos($paths)
    {
        $url = $this->host . self::SHORT_CODE_PATH;
        $timeStamp = time();
        $sign = md5($this->appId . $this->appKey . $timeStamp);
        $query = [
            'app_id' => $this->appId,
            'timestamp' => $timeStamp,
            'sign' => $sign,
        ];
        $params = [
            'short_code_list' => $paths
        ];
        $response = Yii::$app->curl->post($url, $params, $query);
        if ($response) {
            if (ArrayHelper::getValue($response, 'code', 1) !== 0) {
                $message = ArrayHelper::getValue($response, 'data.message');
                throw new \Exception($response);
            }
            $data = $response['result'];
        } else {
            throw new \Exception('无法获取附件数据');
        }

        return ArrayHelper::map($data, 'short_code', 'file_info');
    }

    public function uploadFile($file, array $postData = [])
    {
        if ($file instanceof SplFileObject) {
            $path = $file->getPathname();
            $filename = $file->getFilename();
        } elseif ($file instanceof UploadedFile) {
            $path = $file->tempName;
            $filename = $file->name;
        } else {
            if (!file_exists($file)) throw new Exception('文件不存在');
        }

        $url = $this->host . self::UPLOAD_URL . '?' . http_build_query($this->getSignParams());
        $data = ['path' => (new \CURLFile($path, '', $filename))];
        $data = array_merge($data, $postData);

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

        $response = curl_exec($curl);
        $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        curl_close($curl);
        if (!$response) {
            throw new Exception("请求失败，未知错误！", $status);
        }
        if ($status == 200) {
            return $this->handleResult($response);
        } else {
            throw new Exception("请求失败,内容:" . $response, $status);
        }
    }

    private function handleResult($response)
    {
        $response = json_decode($response, true);
        if (!isset($response['code']) || $response['code'] > 0) {
            throw new Exception('上传文件错误: ' . ($response['message'] ?? ''));
        }
        return $response['result'];
    }

    private function getSignParams()
    {
        $timestamp = time();
        return [
            'app_id' => $this->appId,
            'timestamp' => $timestamp,
            'sign' => md5($this->appId . $this->appKey . strval($timestamp))
        ];
    }

    /**
     * 本地文件上传文件服务
     * @param SplFileObject $file 具体文件
     * @param string|null $type 文件类型 1：图片 2：文件 3：音频 4：视频 若不传递会根据扩展名自动判断
     * @param string|null $ext 文件扩展名 若不传递会使用上传文件名中的扩展名
     * @param array $other_params
     * @return string
     * @throws Exception
     */
    public function uploadServerFile(SplFileObject $file, ?string $type = null, ?string $ext = null, $other_params = [])
    {
        $post_data = array_merge(
            ['type' => $type ?? $this->getFileTypeByExt($ext ?? $file->getExtension())],
            $other_params
        );
        isset($ext) && $post_data['extension_name'] = $ext;
        $result = $this->uploadFile($file, $post_data);

        return $result['path'];
    }

    public function getFileByShort($short, $filename)
    {
        $url = $this->filePath . '/' . $short;
        $content = file_get_contents($url);
        return file_put_contents($filename, $content);
    }

    public function getFileTypeByExt($ext): string
    {
        switch ($ext) {
            case 'mp3':
            case 'amr':
            case 'wav':
            case 'acc':
                return self::FILE_TYPE_AUDIO;
                break;
            case 'jpg':
            case 'png':
            case 'gif':
            case 'jpeg':
            case 'tif':
            case 'tiff':
            case 'bmp':
            case 'pcx':
            case 'tga':
            case 'exif':
            case 'svg':
            case 'psd':
            case 'pcd':
                return self::FILE_TYPE_IMG;
                break;
            case 'mp4':
            case 'avi':
            case 'rm':
            case 'rmvb':
            case 'asf':
            case 'mov':
            case 'wmv':
            case '3gp':
            case 'flv':
            case 'f4v':
                return self::FILE_TYPE_VEDIO;
                break;
            case 'doc':
            case 'txt':
            case 'csv':
            case 'xlsx':
            case 'xls':
            case 'ppt':
            case 'pptx':
            case 'docx':
            case 'json':
            case 'md':
            case 'xml':
            case 'pdf':
            default:
                return self::FILE_TYPE_FILE;
                break;
        }
    }
}